using System;
using System.IO;
using System.Text;
using System.Reflection;
using System.Collections.Generic;
using System.Net;
using System.Data;
using System.Text.RegularExpressions;

using PRoCon.Core;
using PRoCon.Core.Plugin;
using PRoCon.Core.Plugin.Commands;
using PRoCon.Core.Players;
using PRoCon.Core.Players.Items;
using PRoCon.Core.Battlemap;
using PRoCon.Core.Maps;

namespace PRoConEvents
{

    public class chat2teamspeak : PRoConPluginAPI, IPRoConPluginInterface
    {
     
        private bool plugin_enabled;
        private string serverName;
		//private string broadcastAllChatToChannelIDs;
        private List<SettingsOption> pluginSettings;
        
		internal class SettingsOption
        {
		    public string Key;
            public string stringValue;
			public bool boolValue;
            public SettingsOption(string key, string value)
            {
                this.Key = key;
                this.stringValue = value;
            }
			
			public SettingsOption(string key, bool value)
            {
                this.Key = key;
				this.stringValue = null;
                this.boolValue = value;
            }
			
			public bool isBool()
			{
				return (this.stringValue==null);
			}
			
			public bool isPOSTable()
			{
				if(this.Key=="TeamspeakBroadcastUrl"){
					return false;
				}else{
					return true;
				}
			}
			
			public override string ToString()
			{
				if(this.isBool()){
					return this.boolValue.ToString();
				}
				else{
					return this.stringValue;
				}
			}
        }
		
		public string getPluginSettings(string key)
		{
            foreach(SettingsOption so in this.pluginSettings)
            {
				if(so.Key==key)
				{
					if(!so.isBool()){
						return so.stringValue;
					}
					else{
						return so.boolValue.ToString();
					}
				}
            }
			return null;
		}
		
		public void removePluginSettings(string key)
		{
            SettingsOption Option = this.pluginSettings.FindLast(delegate(SettingsOption option)
			{
				return (option.Key == key);
			});
			if (Option != null)
			{
				this.pluginSettings.Remove(Option);
			}
		}

		
        public chat2teamspeak()
        {
            this.pluginSettings = new List<SettingsOption>();
			//this.broadcastAllChatToChannelIDs = null;
            
            // Cfg...
            this.pluginSettings.Add(new SettingsOption("TeamspeakBroadcastUrl", "http://"));
            this.pluginSettings.Add(new SettingsOption("useServerName", true));
            
            // All Users - bypass other broadcast related settings, exept blacklist
            this.pluginSettings.Add(new SettingsOption("broadcastPrivateMessageToAllUserEnabled", false));
            this.pluginSettings.Add(new SettingsOption("broadcastPokeToAllUserEnabled", false));
            
            // All Channels - bypass other broadcast related settings, exept blacklist
            this.pluginSettings.Add(new SettingsOption("broadcastMessageToAllChannelEnabled", false));
            
            // Specific Channel
            this.pluginSettings.Add(new SettingsOption("broadcastToSpecificChannelEnabled", false));
            this.pluginSettings.Add(new SettingsOption("broadcastToSpecificChannelIDs", ""));
            this.pluginSettings.Add(new SettingsOption("broadcastToSpecificChannelNames", ""));
            
            // Specific User - Private Message
            this.pluginSettings.Add(new SettingsOption("broadcastPrivateMessageToSpecificUserEnabled", false));
            this.pluginSettings.Add(new SettingsOption("broadcastPrivateMessageToSpecificUserIDs", ""));
            this.pluginSettings.Add(new SettingsOption("broadcastPrivateMessageToSpecificUserNames", ""));
            // Specific User - Poke
            this.pluginSettings.Add(new SettingsOption("broadcastPokeToSpecificUserEnabled", false));
            this.pluginSettings.Add(new SettingsOption("broadcastPokeToSpecificUserIDs", ""));
            this.pluginSettings.Add(new SettingsOption("broadcastPokeToSpecificUserNames", ""));
            
            // User in Group - Private Message
            this.pluginSettings.Add(new SettingsOption("broadcastPrivateMessageToUserInGroupEnabled", false));
            this.pluginSettings.Add(new SettingsOption("broadcastPrivateMessageToUserInGroupIDs", ""));
            this.pluginSettings.Add(new SettingsOption("broadcastPrivateMessageToUserInGroupNames", ""));
            // User in Group - Poke
            this.pluginSettings.Add(new SettingsOption("broadcastPokeToUserInGroupEnabled", false));
            this.pluginSettings.Add(new SettingsOption("broadcastPokeToUserInGroupIDs", ""));
            this.pluginSettings.Add(new SettingsOption("broadcastPokeToUserInGroupNames", ""));
            
            // User in Channel - Private Message
            this.pluginSettings.Add(new SettingsOption("broadcastPrivateMessageToUserInChannelEnabled", false));
            this.pluginSettings.Add(new SettingsOption("broadcastPrivateMessageToUserInChannelIDs", ""));
            this.pluginSettings.Add(new SettingsOption("broadcastPrivateMessageToUserInChannelNames", ""));
            // User in Channel - Poke
            this.pluginSettings.Add(new SettingsOption("broadcastPokeToUserInChannelEnabled", false));
            this.pluginSettings.Add(new SettingsOption("broadcastPokeToUserInGroupIDs", ""));
            this.pluginSettings.Add(new SettingsOption("broadcastPokeToUserInGroupNames", ""));
            
			// All chat
			//this.pluginSettings.Add(new SettingsOption("broadcastAllChatToChannelIDs", ""));
			
			
            // Blacklist - they will never receive the broadcast
            this.pluginSettings.Add(new SettingsOption("broadcastBlacklistEnabled", false));
            this.pluginSettings.Add(new SettingsOption("broadcastBlacklistUserIDs", ""));
            this.pluginSettings.Add(new SettingsOption("broadcastBlacklistGroupIDs", ""));
            this.pluginSettings.Add(new SettingsOption("broadcastBlacklistChannelIDs", ""));
             
        }
		
		public bool HttpPost(string URI, string Parameters)
		{
			try{
				System.Net.WebRequest req = System.Net.WebRequest.Create(URI);
				//req.Proxy = new System.Net.WebProxy(ProxyString, true);
				req.ContentType = "application/x-www-form-urlencoded";
				req.Method = "POST";
				byte [] bytes = System.Text.Encoding.ASCII.GetBytes(Parameters);
				req.ContentLength = bytes.Length;
				System.IO.Stream os = req.GetRequestStream ();
				os.Write (bytes, 0, bytes.Length); //Push it out there
				os.Close ();
				//System.Net.WebResponse resp = req.GetResponse();
				//if (resp== null) return null;
				//System.IO.StreamReader sr = new System.IO.StreamReader(resp.GetResponseStream());
				//return sr.ReadToEnd().Trim();
				return true;
			}
			catch(Exception exc){
				return false;
			}
		}
		
        public void broadcastToHttp(string playerName, string playerMessage)
        {
			this.HttpPost(this.getPluginSettings("TeamspeakBroadcastUrl"), this.queryStringFactory(playerName, playerMessage, ""));
        }
		public void broadcastToHttp(string playerName, string playerMessage, string configOverride)
        {
			this.HttpPost(this.getPluginSettings("TeamspeakBroadcastUrl"), this.queryStringFactory(playerName, playerMessage, configOverride));
        }
		
		public string queryStringFactory(string playerName, string playerMessage, string append)
        {
			StringBuilder sb = new StringBuilder();

            foreach(SettingsOption so in this.pluginSettings)
            {
				if(so.isPOSTable())
				{
					sb.Append(so.Key);sb.Append("=");sb.Append(so.ToString());sb.Append("&");
				}
            }
			sb.Append("serverName");sb.Append("=");sb.Append(this.serverName);sb.Append("&");
			sb.Append("playerName");sb.Append("=");sb.Append(playerName);sb.Append("&");
			sb.Append("playerMessage");sb.Append("=");sb.Append(playerMessage);sb.Append("&");
			sb.Append(append);sb.Append("&");
			
			return sb.ToString();
        }
		
        private void TextAction(string strSpeaker, string strMessage)
        {
            //this.ConsoleWrite("TextAction [" + strSpeaker + "] " + strMessage);

            /**/
            bool cmdAdmin = Regex.Match(strMessage, @"\s*[!@/]\s*admin", RegexOptions.IgnoreCase).Success;
            bool wordAdmin = Regex.Match(strMessage, @"admin", RegexOptions.IgnoreCase).Success;
            bool wordCheat = Regex.Match(strMessage, @"cheat", RegexOptions.IgnoreCase).Success;
			
            bool cmdAuthor = Regex.Match(strMessage, @"\s*[!@/]\s*"+this.GetPluginAuthor(), RegexOptions.IgnoreCase).Success;
            /**/

            if ((cmdAdmin || wordAdmin || wordCheat) && strSpeaker!="Server")
            {

                this.broadcastToHttp(strSpeaker, strMessage);
            }

            if (cmdAuthor)
            {
                this.ExecuteCommand("procon.protected.send", "admin.say", "[INFO] This server use "+this.GetPluginAuthor()+"'s '"+this.GetPluginName()+"' plugin", "all");
            }
            
        }
		
        public void OnPlayerKilled(Kill killInfo)
        {       
        }
        public void OnGlobalChat(string strSpeaker, string strMessage)
        {
            this.TextAction(strSpeaker, strMessage);
        }
        public void OnTeamChat(string strSpeaker, string strMessage, int iTeamID)
        {
            this.TextAction(strSpeaker, strMessage);
        }
		
        public void OnSquadChat(string strSpeaker, string strMessage, int iTeamID, int iSquadID)
        {
            this.TextAction(strSpeaker, strMessage);
        }
		
        public void OnPlayerLeft(string strSoldierName)
        {
        }
        public void OnRoundOver(int iWinningTeamID)
        {
        }
        private void ConsoleWrite(string msg)
        {
            string prefix = "[^b" + GetPluginName() + "^n] ";
            this.ExecuteCommand("procon.protected.pluginconsole.write", prefix + msg);
        }
        private void KillPlayer(string SoldierName, string strMessage)
        {
            this.ExecuteCommand("procon.protected.send", "admin.killPlayer", SoldierName);
        }
		
		public void OnServerInfo(CServerInfo csiServerInfo)
        {
            this.serverName = csiServerInfo.ServerName;
        }
        public void OnPluginEnable()
        {
            this.plugin_enabled = true;
            ConsoleWrite("Enabled");
            this.ExecuteCommand("procon.protected.send", "admin.say", "Plugin info: Alert !admin enabled", "all");
			
			this.broadcastToHttp("Procon Frostbite", "OnPluginEnable");
			//this.broadcastAllChatToChannelIDs = this.getPluginSettings("broadcastAllChatToChannelIDs");
        }
        public void OnPluginDisable()
        {
            this.plugin_enabled = false;
            ConsoleWrite("Disabled");
            //this.ExecuteCommand("procon.protected.send", "admin.say", "Plugin info: Alert !admin disabled", "all");
			this.broadcastToHttp("Procon Frostbite", "OnPluginDisable");
        }
        public string GetPluginName()
        {
            return "chat2teamspeak";
        }
        public string GetPluginVersion()
        {
            return "0.0.0.1";
        }
        public string GetPluginAuthor()
        {
            return "lethak";
        }
        public string GetPluginWebsite()
        {
            return "lethak@imperialbase.net";
        }
        public string GetPluginDescription()
        {
            return "Redirect ingame chat to any teamspeak server you can query on - Configure with multiple value using the pipe (|) separator";
        }
        public List<CPluginVariable> GetDisplayPluginVariables()
        {
            List<CPluginVariable> lstReturn = new List<CPluginVariable>();
            lstReturn  = this.GetPluginVariables();
            return lstReturn;
        }
        
        public List<CPluginVariable> GetPluginVariables()
        {
		    List<CPluginVariable> lstReturn = new List<CPluginVariable>();
            foreach(SettingsOption so in this.pluginSettings)
            {
				if(!so.isBool()){
					lstReturn.Add(new CPluginVariable(so.Key, typeof(string), so.stringValue));
				}
				else{
					lstReturn.Add(new CPluginVariable(so.Key, typeof(bool), so.boolValue));
				}
            }
            return lstReturn;
        }
        
        public void SetPluginVariable(string key, string Value)
        {
			this.removePluginSettings(key);
            this.pluginSettings.Add(new SettingsOption(key, Value));
        }
		public void SetPluginVariable(string key, bool Value)
        {
			this.removePluginSettings(key);
            this.pluginSettings.Add(new SettingsOption(key, Value));
        }
		
        public void OnPluginLoaded(string strHostName, string strPort, string strPRoConVersion)
        {
			
        }

    }

}
